package info.maxhis.util;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 该类实现了公历与农历互转，支持的范围为1950～2050.</br>
 * 传入和返回的参数都为“yyyy-MM-dd”的字符串。
 * 
 * @author iStar
 */
public class LunarUtil {
	/** 农历从1950年开始 */
	private static final int START_YEAR = 1950;
	
	private static SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd");
	/**	公历月份天数 */
	private static final int[] mSolarDays = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
	/**	汉语农历月份*/
	public static final String[] mLunarMonths = {
		"正", "二", "三", "四", "五", "六", "七","八", "九", "十","十一", "十二"
	};
	
	/**	汉语农历日期*/
	public static final String[] mLunarDays = {
		"初一","初二","初三","初四","初五","初六","初七","初八","初九","初十",
		"十一","十二","十三","十四","十五","十六","十七","十八","十九","二十",
		"廿一","廿二","廿三","廿四","廿五","廿六","廿七","廿八","廿九","三十"
	};
	
	private static final int[][] mLunarMonthDays = {
		//差：该年的农历正月初一到该年公历1月1日的天数；1~12：农历月份天数；闰：如有闰月，记录该月平月天数
		//	 差  1  2  3  4  5  6  7  8  9 10 11 12 闰
			{47,29,30,30,29,30,30,29,29,30,29,30,29},
			{36,30,29,30,30,29,30,29,30,29,30,29,30},
		    { 6,29,30,29,30,59,29,30,30,29,30,29,30,29},    //五月29 闰五月30
		   	{44,29,30,29,29,30,30,29,30,30,29,30,29},
		    {33,30,29,30,29,29,30,29,30,30,29,30,30},
		    {23,29,30,59,29,29,30,29,30,29,30,30,30,29},    //三月29 闰三月30
		    {42,29,30,29,30,29,29,30,29,30,29,30,30},
		    {30,30,29,30,29,30,29,29,59,30,29,30,29,30},    //八月30 闰八月29
		    {48,30,30,30,29,30,29,29,30,29,30,29,30},
		    {38,29,30,30,29,30,29,30,29,30,29,30,29},
		    {27,30,29,30,29,30,59,30,29,30,29,30,29,30},    //六月30 闰六月29
		    {45,30,29,30,29,30,29,30,30,29,30,29,30},
		    {35,29,30,29,29,30,29,30,30,29,30,30,29},
		    {24,30,29,30,58,30,29,30,29,30,30,30,29,29},    //四月29 闰四月29
		    {43,30,29,30,29,29,30,29,30,29,30,30,30},
		    {32,29,30,29,30,29,29,30,29,29,30,30,29},
		    {20,30,30,59,30,29,29,30,29,29,30,30,29,30},    //三月30 闰三月29
		    {39,30,30,29,30,30,29,29,30,29,30,29,30},
		    {29,29,30,29,30,30,29,59,30,29,30,29,30,30},    //七月30 闰七月29
		    {47,29,30,29,30,29,30,30,29,30,29,30,29},
		    {36,30,29,29,30,29,30,30,29,30,30,29,30},
		    {26,29,30,29,29,59,30,29,30,30,30,29,30,30},    //五月30 闰五月29
		    {45,29,30,29,29,30,29,30,29,30,30,29,30},
		    {33,30,29,30,29,29,30,29,29,30,30,29,30},
		    {22,30,30,29,59,29,30,29,29,30,30,29,30,30},    //四月30 闰四月29
		    {41,30,30,29,30,29,29,30,29,29,30,29,30},
		    {30,30,30,29,30,29,30,29,59,29,30,29,30,30},    //八月30 闰八月29
		    {48,30,29,30,30,29,30,29,30,29,30,29,29},
		    {37,30,29,30,30,29,30,30,29,30,29,30,29},
		    {27,30,29,29,30,29,60,29,30,30,29,30,29,30},    //六月30 闰六月30
		    {46,30,29,29,30,29,30,29,30,30,29,30,30},
		    {35,29,30,29,29,30,29,29,30,30,29,30,30},
		    {24,30,29,30,58,30,29,29,30,29,30,30,30,29},    //四月29 闰四月29
		    {43,30,29,30,29,29,30,29,29,30,29,30,30},
		    {32,30,29,30,30,29,29,30,29,29,59,30,30,30},    //十月30 闰十月29
		    {50,29,30,30,29,30,29,30,29,29,30,29,30},
		    {39,29,30,30,29,30,30,29,30,29,30,29,29},
		    {28,30,29,30,29,30,59,30,30,29,30,29,29,30},    //六月30 闰六月29
		    {47,30,29,30,29,30,29,30,30,29,30,30,29},
		    {36,30,29,29,30,29,30,29,30,29,30,30,30},
		    {26,29,30,29,29,59,29,30,29,30,30,30,30,30},    //五月30 闰五月29
		    {45,29,30,29,29,30,29,29,30,29,30,30,30},
		    {34,29,30,30,29,29,30,29,29,30,29,30,30},
		    {22,29,30,59,30,29,30,29,29,30,29,30,29,30},    //三月30 闰三月29
		    {40,30,30,30,29,30,29,30,29,29,30,29,30},
		    {30,29,30,30,29,30,29,30,59,29,30,29,30,30},    //八月30 闰八月29
		    {49,29,30,29,30,30,29,30,29,30,30,29,29},
		    {37,30,29,30,29,30,29,30,30,29,30,30,29},
		    {27,30,29,29,30,58,30,30,29,30,30,29,30,29},    //五月29 闰五月29
		    {46,30,29,29,30,29,29,30,29,30,30,30,29},
		    {35,30,30,29,29,30,29,29,30,29,30,30,29},
		    {23,30,30,29,59,30,29,29,30,29,30,29,30,30},    //四月30 闰四月29
		    {42,30,30,29,30,29,30,29,29,30,29,30,29},
		    {31,30,30,29,30,30,29,30,29,29,30,29,30},
		    {21,29,59,30,30,29,30,29,30,29,30,29,30,30},    //二月30 闰二月29
		    {39,29,30,29,30,29,30,30,29,30,29,30,29},
		    {28,30,29,30,29,30,29,59,30,30,29,30,30,30},    //七月30 闰七月29
		    {48,29,29,30,29,29,30,29,30,30,30,29,30},
		    {37,30,29,29,30,29,29,30,29,30,30,29,30},
		    {25,30,30,29,29,59,29,30,29,30,29,30,30,30},    //五月30 闰五月29
		    {44,30,29,30,29,30,29,29,30,29,30,29,30},
		    {33,30,29,30,30,29,30,29,29,30,29,30,29},
		    {22,30,29,30,59,30,29,30,29,30,29,30,29,30},    //四月30 闰四月29
		    {40,30,29,30,29,30,30,29,30,29,30,29,30},
		    {30,29,30,29,30,29,30,29,30,59,30,29,30,30},    //九月30 闰九月29
		    {49,29,30,29,29,30,29,30,30,30,29,30,29},
		    {38,30,29,30,29,29,30,29,30,30,29,30,30},
		    {27,29,30,29,30,29,59,29,30,29,30,30,30,29},    //六月29 闰六月30
		    {46,29,30,29,30,29,29,30,29,30,29,30,30},
		    {35,30,29,30,29,30,29,29,30,29,29,30,30},
		    {24,29,30,30,59,30,29,29,30,29,30,29,30,30},    //四月30 闰四月29
		    {42,29,30,30,29,30,29,30,29,30,29,30,29},
		    {31,30,29,30,29,30,30,29,30,29,30,29,30},
		    {21,29,59,29,30,30,29,30,30,29,30,29,30,30},    //二月30 闰二月29
		    {40,29,30,29,29,30,29,30,30,29,30,30,29},
		    {28,30,29,30,29,29,59,30,29,30,30,30,29,30},    //六月30 闰六月29
		    {47,30,29,30,29,29,30,29,29,30,30,30,29},
		    {36,30,30,29,30,29,29,30,29,29,30,30,29},
		    {25,30,30,30,29,59,29,30,29,29,30,30,29,30},    //五月30 闰五月29
		    {43,30,30,29,30,29,30,29,30,29,29,30,30},
		    {33,29,30,29,30,30,29,30,29,30,29,30,29},
		    {22,29,30,59,30,29,30,30,29,30,29,30,29,30},    //三月30 闰三月29
		    {41,30,29,29,30,29,30,30,29,30,30,29,30},
		    {30,29,30,29,29,30,29,30,29,30,30,59,30,30},    //十一月30 闰十一月29
		    {49,29,30,29,29,30,29,30,29,30,30,29,30},
		    {38,30,29,30,29,29,30,29,29,30,30,29,30},
		    {27,30,30,29,30,29,59,29,29,30,29,30,30,29},    //六月29 闰六月30
		    {45,30,30,29,30,29,29,30,29,29,30,29,30},
		    {34,30,30,29,30,29,30,29,30,29,29,30,29},
		    {23,30,30,29,30,59,30,29,30,29,30,29,29,30},    //五月30 闰五月29
		    {42,30,29,30,30,29,30,29,30,30,29,30,29},
		    {31,29,30,29,30,29,30,30,29,30,30,29,30},
		    {21,29,59,29,30,29,30,29,30,30,29,30,30,30},    //二月30 闰二月29
		    {40,29,30,29,29,30,29,29,30,30,29,30,30},
		    {29,30,29,30,29,29,30,58,30,29,30,30,30,29},    //七月29 闰七月29
		    {47,30,29,30,29,29,30,29,29,30,29,30,30},
		    {36,30,29,30,29,30,29,30,29,29,30,29,30},
		    {25,30,29,30,30,59,29,30,29,29,30,29,30,29},    //五月29 闰五月30
		    {44,29,30,30,29,30,30,29,30,29,29,30,29},
		    {32,30,29,30,29,30,30,29,30,30,29,30,29},
		    {22,29,30,59,29,30,29,30,30,29,30,30,29,29},    //三月29 闰三月30		
	};
	
	/**
	 *  是否闰年
	 */
	private static boolean isLeapYear(int year) {
		return (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0));
	}
	
	/**
	 * 公历该月的天数(year：年份； month：月份)
	 */
	private static int getDays(int year, int month) {
		if (isLeapYear(year) && month == 2)
			return 29;
		else
			return mSolarDays[month-1];
	}
	
	private String getLunarMonth(int month) {
		if (month >= 1 && month <= 12) {
			return mLunarMonths[month - 1];
		}
		return "" + month;
	}
	
	private String getLunarDay(int day) {
		if(day >=1 && day <=30 ) {
			return mLunarDays[day-1];
		} 
		return "" + day;
	}
	
	/**
	 * 公历转农历
	 * @param date 公历日期（yyyy-MM-dd）
	 * @return yyyy-MM-dd
	 */
	public static String solar2Lunar(String date) {

		String[] dates = date.split("-");
		int year = Integer.parseInt(dates[0]);
		int month = Integer.parseInt(dates[1]);
		int day = Integer.parseInt(dates[2]);

		int lYear = year, lMonth = month, lDay = day, type = 0;

		if (year <= 1951 || month <= 0 || day <= 0 || year >= 2051) {
			return "Bad date format ! Only support year from 1951 to 2050.";
		}
		Date date1 = null, date2 = null;
		try {
			date1 = mDateFormat.parse(year + "-01-01");// 当年1月1日
			date2 = mDateFormat.parse(date);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		// 获取查询日期到当年1月1日的天数
		int days = (int) ((date2.getTime() - date1.getTime()) /1000 / 3600 / 24);
		days += 1;

		// 获取相应年度农历数据，化成数组Larray
		int[] monthDays = mLunarMonthDays[year - START_YEAR];
		if (days <= monthDays[0]) {
			lYear = year - 1;
			days = monthDays[0] - days;
			monthDays = mLunarMonthDays[lYear - START_YEAR];
			if (days < monthDays[12]) {
				lMonth = 12;
				lDay = monthDays[12] - days;
			} else {
				lMonth = 11;
				days = days - monthDays[12];
				lDay = monthDays[11] - days;
			}
		} else {
			lYear = year;
			days = days - monthDays[0];
			for (int i = 1; i <= 12; i++) {
				if (days > monthDays[i])
					days = days - monthDays[i];
				else {
					if (days > 30) {
						days = days - monthDays[13];
						type = 1;
					}

					lMonth = i;
					lDay = days;
					break;
				}
			}
		}
		return lYear + "-" + (type==1?"闰":"") + lMonth + "-" + lDay ;
	}
	
	/**
	 * 农历转公历
	 * @param date 	农历日期
	 * @return "yyyy-MM-dd"
	 */
	public static String lunar2Solar(String date) {
		return lunar2Solar(date,0);
	}
	
	/**
	 * 农历转公历
	 * @param date 	农历日期
	 * @param type	1 for 闰年，0 for otherwise
	 * @return "yyyy-MM-dd"
	 */
	public static String lunar2Solar(String date, int type) {
		String[] dates = date.split("-");
		int year = Integer.parseInt(dates[0]);
		int month = Integer.parseInt(dates[1]);
		int day = Integer.parseInt(dates[2]);

		int sYear = year;
		int sMonth = month;
		int sDay = day;

		if (year <= 1950 || month <= 0 || day <= 0 || year >= 2051) {
			return "Bad date format ! Only support year from 1951 to 2050.";
		}
		int[] monthDays = mLunarMonthDays[year - START_YEAR];
		if (type == 1 && monthDays.length <= 13) {
			return "Not leap year!";// 要求查询闰，但查无闰月
		}

		// 如果查询的农历是闰月并该年度农历数组存在闰月数据就获取
		if (monthDays[month] > 30 && type == 1 && monthDays.length >= 13)
			day = monthDays[13] + day;
		// 获取该年农历日期到公历1月1日的天数
		int days = day;
		for (int i = 0; i <= month - 1; i++)
			days += monthDays[i];
		// 当查询农历日期距离公历1月1日超过一年时
		if (days > 366 || (getDays(month, 2) != 29 && days > 365)) {
			sYear = year + 1;
			if (getDays(month, 2) != 29)
				days -= 366;
			else
				days -= 365;
			if (days > mSolarDays[1]) {
				sMonth = 2;
				sDay = days - mSolarDays[1];
			} else {
				sMonth = 1;
				sDay = days;
			}
		} else {
			sYear = year;
			for (int i = 1; i <= 12; i++) {
				if (days > getDays(sYear, i))
					days -= getDays(sYear, i);
				else {
					sMonth = i;
					sDay = days;
					break;
				}
			}
		}
		return sYear + "-" + sMonth + "-" + sDay;
	}

	public static void main(String[] args) {
		System.out.println(LunarUtil.solar2Lunar("2012-4-6"));
		System.out.println(LunarUtil.lunar2Solar("2017-3-9",1));
	}
}
